package com.gopay.cashier.service.impl;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.dao.CpsRefundManualLogDAO;
import com.gopay.cashier.service.BankPayCallBackService;
import com.gopay.cashier.service.gsrt.GsrtService;
import com.gopay.cashier.web.command.BankPayCallbackCommand;
import com.gopay.common.constants.Constants;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.GatewaySource;
import com.gopay.common.constants.trans.PayChannel;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.cps.dao.bank.BankOrderQueryDAO;
import com.gopay.common.cps.dao.order.CpsGeneralMainOrderQueryDAO;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.cps.manager.bank.BankOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bis.BisBankInfoMain;
import com.gopay.common.domain.cashier.BankCardType;
import com.gopay.common.domain.cashier.PayDoneResult;
import com.gopay.common.domain.cashier.PayWay;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.domain.cps.CpsRefundManualLog;
import com.gopay.common.exception.GopayException;
import com.gopay.remote.cps.bis.ErrOrderRecordRemoteService;
import com.gopay.remote.cps.cashier.CashierFailedOrderNotifyRemoteService;
import com.gopay.remote.cps.cashier.CashierPayCallbackRemoteService;
import com.gopay.remote.cps.expresspay.EpBankCardRemoteService;
import com.gopay.remote.order.MainOrderUpdateRemoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created by Administrator on 14-2-25.
 */
@Service("bankPayCallBackService")
public class BankPayCallBackServiceImpl implements BankPayCallBackService {

    protected final static Log logger = LogFactory.getLog(BankPayCallBackServiceImpl.class);

    @Resource(name="cpsGeneralMainOrderQueryDAO")
    private CpsGeneralMainOrderQueryDAO cpsGeneralMainOrderQueryDAO;

    @Resource(name = "mainOrderUpdateService")
    protected MainOrderUpdateRemoteService mainOrderUpdateService;

    @Resource(name = "cashierPayCallbackService")
    protected CashierPayCallbackRemoteService cashierPayCallbackService;

    @Resource(name = "epBankCardService")
    private EpBankCardRemoteService epBankCardService;

    @Resource(name = "cpsGeneralReceiptOrderQueryDAO")
    private CpsGeneralReceiptOrderQueryDAO cpsGeneralReceiptOrderQueryDAO;
    
    @Resource(name="gsrtService")
    private GsrtService gsrtService;

    @Resource(name = "cbcashierPayCallbackService")
    protected CashierPayCallbackRemoteService cbcashierPayCallbackService;
    
    @Resource(name = "cashierCpsRefundManualLogDAO")
    protected CpsRefundManualLogDAO cashierCpsRefundManualLogDAO;

    @Resource(name = "errOrderRecordService")
    protected ErrOrderRecordRemoteService errOrderRecordService;

    @Resource(name = "cashierFailedOrderNotifyRemoteService")
    protected CashierFailedOrderNotifyRemoteService cashierFailedOrderNotifyRemoteService;

    @Resource(name = "bankOrderQueryManager")
    protected BankOrderQueryManager bankOrderQueryManager;
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
    public boolean callBackProcess(BankPayCallbackCommand command) throws GopayException{
        boolean dealRes = false;
        CpsGenMainOrder order =  cpsGeneralMainOrderQueryDAO.find(CpsGenMainOrder.class,command.getOrderId());

        if (null == order) {
            logger.error("订单不存在！main order not exist!" + command.getOrderId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        // 验证，如果订单已处理，则该流程终止
        if (TxnStaCode.TXN_STA_CD_20000.value == order.getTxnStaCd()){
            logger.error("the order txnStaCd is 20000 has finished for " + order.getGopayOrderId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5111);
        }

        //手机钱包发红包，三充交易单独处理是否重复的银行通知
        if( IntTxnCd._01608.value.equals(order.getGopayIntTxnCd())
                || IntTxnCd._01611.value.equals(order.getGopayIntTxnCd())
                || IntTxnCd._01612.value.equals(order.getGopayIntTxnCd())
                || IntTxnCd._01613.value.equals(order.getGopayIntTxnCd())){
            // 验证，如果是付款成功，则该流程终止
            if ( TxnStaCode.TXN_STA_CD_30402.value == order.getTxnStaCd()
                    || TxnStaCode.TXN_STA_CD_30501.value == order.getTxnStaCd()
                    || TxnStaCode.TXN_STA_CD_90502.value == order.getTxnStaCd()
                    || TxnStaCode.TXN_STA_CD_90503.value == order.getTxnStaCd()
                    || TxnStaCode.TXN_STA_CD_90504.value == order.getTxnStaCd() ){
                logger.error("手机钱包 has finished for " + order.getGopayOrderId());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5111);
            }
        }

        // ------------验证，如果订单已处理，则该流程终止 lx 退款优化新增 2016-10-18 19:11:13 start----------
        DetachedCriteria criteria = DetachedCriteria.forClass(CpsRefundManualLog.class);
        criteria.add(Restrictions.eq("gopayOrderId", command.getOrderId()));
        criteria.add(Restrictions.eq("status",CpsRefundManualLog.OPERATOR_FINAL_TYPE));
        List<CpsRefundManualLog> list = cashierCpsRefundManualLogDAO.findByCriteria(criteria);
        //若果 手动修改过 该订单 在状态表中会有记录   
        if (!list.isEmpty()) {
            logger.error("该订单状态已在console进行手动修改,并完成退款及账务处理操作,订单号:" + order.getGopayOrderId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5111);
        }
        // ------------验证，如果订单已处理，则该流程终止 lx 退款优化新增 2016-10-18 19:11:13 end----------
        
//        if (TxnStaCode.TXN_STA_CD_30102.value == order.getTxnStaCd()){
//            int acps = acctTransService.checkAcpsAcctTransDtl(order.getGopayOrderId());
//            logger.error("the order txnStaCd is 30102 for " + order.getGopayOrderId()+" has acpsTransCount: "+acps);
//            if(acps < 0)
//                return false;
//            if(acps > 0){
//                //已入账，更新主订单订单状态为20000成功
//               List<String> oriTxnStaCd = new ArrayList<String>();
//                 oriTxnStaCd.add(String.valueOf(TxnStaCode.TXN_STA_CD_20000.value));
//                 oriTxnStaCd.add(String.valueOf(TxnStaCode.TXN_STA_CD_30102.value));
//                 return mainOrderUpdateService.updateTxnStaCd(order.getGopayOrderId(), "" + TxnStaCode.TXN_STA_CD_30102.value, oriTxnStaCd, true);
//            }
//        }

        // 根据bis返回结果构造PayDoneResult
        PayDoneResult r = getPayDoneResult(command, order);
        //更新订单状态
        if (TxnStaCode.TXN_STA_CD_30102.value != order.getTxnStaCd()){
            logger.info("根据bis返回结果更新订单状态--orderId是"+order.getGopayOrderId()+",ori_status_"+order.getTxnStaCd());
            updateOrder(r);
        }
        // 调用cps更新订单支付状态
        if (r.isSuccess()) {
            dealRes = completeOrder(r);
        } else {
        	// 退款交易失败账务处理 add by zhengxue 20160902
            if (IntTxnCd._01200.value.equals(order.getGopayIntTxnCd())||IntTxnCd._02302.value.equals(order.getGopayIntTxnCd())
                    || IntTxnCd._09900.value.equals(order.getGopayIntTxnCd())
                    || IntTxnCd._09901.value.equals(order.getGopayIntTxnCd())) {   
            	/**
            	 * 原失败订单判断条件有问题，order拿到的状态是订单没有跟新前的状态30101.
            	 * xgh修改为根据r对象判断是否成功。
            	 */
//            	if (TxnStaCode.TXN_STA_CD_90101.value == order.getTxnStaCd()) {
//            		logger.error("pay refund fail deal where order is "
//                            + order.getGopayOrderId());
//            		dealRes = completeOrder(r);
//            		return dealRes;
//            	}
            	if (!r.isSuccess()) {
        		logger.error("pay refund fail deal where order is "
                        + order.getGopayOrderId());
        		dealRes = completeOrder(r);
        		return dealRes;
        	}
            }
            if (TxnStaCode.TXN_STA_CD_90101.value == order.getTxnStaCd()) {
                CpsGenReceiptOrder cpsGenReceiptOrder = cpsGeneralReceiptOrderQueryDAO.find(CpsGenReceiptOrder.class, order.getGopayOrderId());
                if (StringUtils.isNotBlank(cpsGenReceiptOrder.getEpBankCardNo())) {
                    if (!epBankCardService.isFreezeCardNo(cpsGenReceiptOrder.getEpBankCardNo())) {
                        logger.error("express pay error process for epBankCardNo " + cpsGenReceiptOrder.getEpBankCardNo() + "where order is "
                                + order.getGopayOrderId());
                        epBankCardService.errAccum4Pay(cpsGenReceiptOrder.getEpBankCardNo());
                    }
                }
                if(StringUtils.equals(order.getGatewaySource(), GatewaySource.GATEWAY_SOURCE_09.value)){
	            	gsrtService.updateGsrtRecharge(order.getGopayOrderId());
	            }
            }

            //银行处理失败，记录银行返回错误信息和更新订单状态  add by liuyong
            errOrderRecordService.updateOrderErrorMsg(r);

            /**** add by sh.jiao 快捷API支付银行明确失败，发送通知给商户 start****/
            BankOrder bankOrder = bankOrderQueryManager.getCheckOrderByGopayOrderId(order.getGopayOrderId());
            logger.error("BANKORDER:"+bankOrder);
            // 交易类型为00100
            if(IntTxnCd._00100.value.equals(order.getGopayIntTxnCd())
                    // 支付方式为快捷api支付
                    && (PayChannel._30.value.equals(order.getPayChannel())
                        || PayChannel._31.value.equals(order.getPayChannel()))
                    // 银行订单状态为99或者91
                    && (BankOrderStatus.BPS_CHECK_FAIL.equals(bankOrder.getOrderStatus())
                        || BankOrderStatus.ORDER_FAIL.equals(bankOrder.getOrderStatus()))) {
                logger.error("快捷API支付订单，银行明确失败，发送商户后台通知，gopayOrderId="+order.getGopayOrderId());
                cashierFailedOrderNotifyRemoteService.doFailedOrderMerNotify(order.getGopayOrderId());
            }
            /**** add by sh.jiao 快捷API支付银行明确失败，发送通知给商户 end****/
        }
        return dealRes;
    }

    private boolean completeOrder(PayDoneResult r) throws GopayException {
        logger.error("银行返回-调用cps执行支付完成处理.BEGIN. call cashierPayCallbackService.finish." + r);
        String result = null;
        try {
            if (isCBRMB(r.getOrderId())) {
                // 调跨境人民币的cps，暂时先这样
                result = cbcashierPayCallbackService.finish(r);
            } else {
                result = cashierPayCallbackService.finish(r);
            }
        } catch (Exception e) {
            logger.error("cashierPayCallbackService completeOrder orderId:"+r.getOrderId()+" error:"+e.getMessage());
        }
        logger.error("银行返回-调用cps执行支付完成处理.END. call cashierPayCallbackService.finish." + result + ", " + r);
        if (!ProcCodeConstants.PROC_CODE_000S1000.equals(result) && !ProcCodeConstants.PROC_CODE_100S1000.equals(result)) {
            throw new GopayException(result);
        }
        return true;
    }

    /**
     * 银行如果返回成功，订单状态更新为：TXN_STA_CD_30102，失败则更新为：TXN_STA_CD_90101
     * @param r
     * @throws GopayException
     */
    private void updateOrder(PayDoneResult r) throws GopayException {
        String sta = "" + (r.isSuccess() ? TxnStaCode.TXN_STA_CD_30102.value : TxnStaCode.TXN_STA_CD_90101.value);
        logger.error("银行返回-调用cps更新订单.BEGIN. call cashierPayCallbackService.finish." + r + ", set TxnStaCd = " + sta);
        List<String> oriTxnStaCd = new ArrayList<String>();
        oriTxnStaCd.add(String.valueOf(TxnStaCode.TXN_STA_CD_20000.value));
        oriTxnStaCd.add(String.valueOf(TxnStaCode.TXN_STA_CD_30102.value));
        //oriTxnStaCd.add(String.valueOf(TxnStaCode.TXN_STA_CD_90002.value)); 生产bug10期 lx 2017-10-19 16:14:51
        oriTxnStaCd.add(String.valueOf(TxnStaCode.TXN_STA_CD_20005.value));
        boolean res = mainOrderUpdateService.updateTxnStaCd(r.getOrderId(), sta, oriTxnStaCd, true);
        logger.info("根据bis返回结果更新订单状态--orderId是"+r.getOrderId()+",new_status_"+sta);
        logger.error("银行返回-调用cps更新订单.END. call cashierPayCallbackService.finish." + r + ", res = " + res);
        if(!res) {
            throw new WebException(ProcCodeConstants.PROC_CODE_200F1002);
        }
    }

    private PayDoneResult getPayDoneResult(BankPayCallbackCommand command, CpsGenMainOrder order) throws WebException {
        logger.error("转换BIS支付结果: " + command);
        PayDoneResult r = new PayDoneResult();
        r.setId(UUID.randomUUID().toString());
        if ("00".equals(command.getRetCode())) {
            r.setSuccess(true);
        } else {
            r.setSuccess(false);
        }
        r.setOrderId(order.getGopayOrderId());
        r.setAmt(new BigDecimal(command.getAmt()));
        r.setCardType(BankCardType.getBankCardType(command.getCardType()));
        r.setNotifyNum(Integer.parseInt(command.getNotifyNum()));
        PayWay pw = getPayWayByOrder(order);
        r.setPayWay(pw);
        r.setRetMsg(command.getRetMsg());
        return r;
    }

    /**
     * 返回正确的支付方式 PayWay
     */
    private PayWay getPayWayByOrder(CpsGenMainOrder order) throws WebException {
        //付款类交易 自动对账，走收银台
        if(StringUtils.equals(order.getGopayIntTxnCd(),IntTxnCd._00700.value) 
        		||StringUtils.equals(order.getGopayIntTxnCd(),IntTxnCd._01301.value) 
        		||StringUtils.equals(order.getGopayIntTxnCd(),IntTxnCd._00800.value)){
            return PayWay.DirectBankPay;
        } else if (IntTxnCd._00666.value.equals(order.getGopayIntTxnCd())) {
            //委托代收交易    不登录网银支
            return PayWay.DirectBankPay;
        } else if (IntTxnCd._00500.value.equals(order.getGopayIntTxnCd())  
        		&& StringUtils.isNotEmpty(order.getRelevanceGopayOrderId())) {
            // 如果 是充值订单，并且有关联的国付宝订单，则为登录后网银支付(包括银行卡全额支付和差额支付)
            return PayWay.PostLoginBankPay;
        } else if ( IntTxnCd._00100.value.equals(order.getGopayIntTxnCd())
                && ( PayChannel._01.value.equals(order.getPayChannel())
                || PayChannel._03.value.equals(order.getPayChannel())
                || PayChannel._06.value.equals(order.getPayChannel())
                || PayChannel._04.value.equals(order.getPayChannel())
                || PayChannel._08.value.equals(order.getPayChannel())
                || PayChannel._51.value.equals(order.getPayChannel()) ) ){
            // 登陆后网关支付和快捷支付，改成直接银行支付
            return PayWay.DirectBankPay;
        } else if (IntTxnCd._01200.value.equals(order.getGopayIntTxnCd())
                || IntTxnCd._09900.value.equals(order.getGopayIntTxnCd())
                || IntTxnCd._09901.value.equals(order.getGopayIntTxnCd())
                || IntTxnCd._02302.value.equals(order.getGopayIntTxnCd())) {
            // 如果收款交易退款、银行卡重复支付冲正、信用卡充值冲正 add by zhengxue 20160902
            return PayWay.RefundBankPay;
        } else if (!IntTxnCd._00500.value.equals(order.getGopayIntTxnCd()) 
        		&& StringUtils.isNotEmpty(order.getPayAcct())) {
            //  by leixiaobao 2016-10-12 天溢盈 ,手机钱包二改一
        	//add by zhoupeng 增加19 第三方app(兜兜天溢盈） 20171027
            if( (GatewaySource.GATEWAY_SOURCE_05.value.equals(order.getGatewaySource()) || GatewaySource.GATEWAY_SOURCE_20.value.equals(order.getGatewaySource()))
                    && PayChannel._02.value.equals(order.getPayChannel())){
                return PayWay.AcctPay;
            }
           //add by zhoupeng 增加19 第三方app(兜兜天溢盈） 20171027
            if( (GatewaySource.GATEWAY_SOURCE_05.value.equals(order.getGatewaySource()) || GatewaySource.GATEWAY_SOURCE_20.value.equals(order.getGatewaySource()))
                    && ( PayChannel._03.value.equals(order.getPayChannel())
                    || PayChannel._06.value.equals(order.getPayChannel())
                    || PayChannel._08.value.equals(order.getPayChannel()) ) ){
                /*支付那笔订单自动出款成功后，会调用此处，后续继续做账充2202到备付金。
                                            后续做账方法在doAccountTrans中，所以PayWay不能给DirectBankPay，要给AcctPay
                  modify by tangyang at 20170411
                */
                if( !IntTxnCd._01605.value.equals(order.getGopayIntTxnCd())
                        && !IntTxnCd._01606.value.equals(order.getGopayIntTxnCd())
                        && !IntTxnCd._01617.value.equals(order.getGopayIntTxnCd())){
                      return PayWay.DirectBankPay;
                  }
            }
            
        	// 如果付款人账户非空，则为虚拟账户支付
            return PayWay.AcctPay;
        } else if (StringUtils.isNotEmpty(order.getOutStlmId()) && !Constants.GFB_BANK_CODE.equalsIgnoreCase(order.getOutStlmId())) {
            // 如果出款清算单位代码 非空，且不是“GFB”，则为不登录网银支付（或者充值交易）
            return PayWay.DirectBankPay;
        } else if(StringUtils.equals(order.getGopayIntTxnCd(),IntTxnCd._01734.value)){//add by qld  跨境新增拨款订单 20170122
            return PayWay.AcctPay;
        } else if (IntTxnCd._02301.value.equals(order.getGopayIntTxnCd())) {
            //聚合支付交易    不登录网银支 add by xuangh
            return PayWay.DirectBankPay;
        }else {
            logger.error("支付方式判断出错！error PayWay !!" + order.getGopayOrderId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5006);
        }
    }

    private boolean isCBRMB(String orderId) {
        CpsGenMainOrder main = cpsGeneralMainOrderQueryDAO.findByGopayOrderId(orderId);
        if (IntTxnCd._01720.value.equals(main.getGopayIntTxnCd())
                || IntTxnCd._01723.value.equals(main.getGopayIntTxnCd())
                || IntTxnCd._01724.value.equals(main.getGopayIntTxnCd())
                || IntTxnCd._01725.value.equals(main.getGopayIntTxnCd())
                || IntTxnCd._01727.value.equals(main.getGopayIntTxnCd())  //add by qld 01727跨境人民币进口的退款，如果走线上退款，会从这儿走
                || IntTxnCd._01734.value.equals(main.getGopayIntTxnCd())
                || IntTxnCd._01735.value.equals(main.getGopayIntTxnCd())
                || IntTxnCd._01738.value.equals(main.getGopayIntTxnCd())) {
            return true;
        } else if ("KJRMBZH".equals(main.getMainRecvAcctProdCode())) {
            logger.info("订单号:" + main.getGopayOrderId() + "是跨境人民币专属账户的充值");
            return true;
        }else if ("KJWKZH".equals(main.getMainRecvAcctProdCode())) {
            logger.info("订单号:" + main.getGopayOrderId() + "是跨境外卡账户的充值");
            return true;
        }else if (IntTxnCd._01732.value.equals(main.getGopayIntTxnCd())) {
            // 跨境汇款的充值订单
            CpsGenMainOrder orgOrder = cpsGeneralMainOrderQueryDAO.find(CpsGenMainOrder.class,
                    main.getRelevanceGopayOrderId());
            if (IntTxnCd._01723.value.equals(orgOrder.getGopayIntTxnCd())
                    || IntTxnCd._01724.value.equals(orgOrder.getGopayIntTxnCd())
                    || IntTxnCd._01725.value.equals(orgOrder.getGopayIntTxnCd())) {
                return true;
            }

        }

        return false;

    }
    

}
